#include "StdAfx.h"
#include "NetworkBase.h"
#include "Exceptions.h"

namespace SpikingNeuronLib
{
	// Public Members -------------------------------------------------------------------------------------------

	NetworkBase::NetworkBase()
	{
	}

	void NetworkBase::Run(int totalSeconds, PatternGenerator^ backgroundPattern)
	{
		this->Run(totalSeconds, backgroundPattern, nullptr);
	}

	void NetworkBase::Run(int totalSeconds, PatternGenerator^ backgroundPattern, IStimulus^ inputPattern)
	{
		if (inputPattern && inputPattern->IsEmpty)
			RunWarning("WARNING: empty input pattern");

		int result = RunImpl(totalSeconds, backgroundPattern, inputPattern);
		if (result)
		{
			// network was not initialized
			String^ message = gcnew String("Network is uninitialized");
			throw gcnew UninitializedException(message);
		}
	}

	void NetworkBase::Run(int startSeconds, int endSeconds, PatternGenerator^ backgroundPattern, IStimulus^ inputPattern)
	{
		if (inputPattern && inputPattern->IsEmpty)
			RunWarning("WARNING: empty input pattern");

		int result = RunImpl(startSeconds, endSeconds, backgroundPattern, inputPattern);
		if (result)
		{
			// network was not initialized
			String^ message = gcnew String("Network is uninitialized");
			throw gcnew UninitializedException(message);
		}
	}

	array<array<int>^>^ NetworkBase::CreateDelayMatrix(int M, int D, int Ne, int Ni)
	{
		// M:        number of synapses per neuron
		// D:        maximal conduction delay
		// Ne:       excitatory neurons
		// Ni:       inhibitory neurons
		int N = Ne + Ni;
		array<array<int>^>^ result = gcnew array<array<int>^>(N);
		for (int i = 0; i < N; i++)
		{
			array<int>^ row = gcnew array<int>(M);
			if (i < Ne)
			{
				int segmentSize = M / D;
				for (int delay = 0; delay < D; delay++)
				{
					for (int span = 0, idx = segmentSize * delay; span < segmentSize; span++, idx++)
					{
						row[idx] = delay;
					}
				}
			}
			else
			{
				for (int idx = 0; idx < M; idx++)
				{
					row[idx] = 1;
				}
			}

			result[i] = row;
		}

		return result;
	}

	List<Triplet^>^ NetworkBase::CreateTripletListFromInputPattern(Stimulus^ inputPattern)
	{
		List<Triplet^>^ tripletList = gcnew List<Triplet^>();
		List<FiringEvent>^ firings = inputPattern->Pattern->EventList;

		// len(n) choose 3
		// where order is not important and repetition is not allowed
        int length = firings->Count;
        for (int i = 0; i < length; i++)
		{
            for (int j = i + 1; j < length; j++)
			{
                for (int k = j + 1; k < length; k++)
				{
					Triplet^ triplet = gcnew Triplet(firings[i], firings[j], firings[k]);
                    tripletList->Add(triplet);
				}
			}
		}

		return tripletList;
	}
}